﻿using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Text;

namespace SharePointSearchBench.Library
{
    /// <summary>
    /// This class is used to generate Full Text searches and eliminates the need
    /// for knowledge of Full Text search syntax.  It can be used to generate
    /// fairly complex WHERE clauses.
    /// </summary>
    /// <example><code>
    /// FullTextBuilder text = FullTextBuilder.Select("Title, Author").Where(Condition.FreeText("dog, cat"));
    /// Search search = new Search();
    /// search.SearchText = text;
    /// </code></example>
    public class FullTextBuilder : SearchText
    {
        string selectClause;
        string whereClause;
        string fromClause;
        string orderClause;

        /// <summary>
        /// Creates a new instance of the class.
        /// </summary>
        private FullTextBuilder()
        {
            this.fromClause = "Scope()";
            this.orderClause = "RANK DESC";
        }

        /// <summary>
        /// Creates a new instance of a FullTextBuilder by specifying the 
        /// fields to return in a Full Text search.
        /// </summary>
        /// <param name="fields">A comma-delimited list of fields to return.</param>
        /// <returns></returns>
        /// <remarks>When using this overload, do not specify a "SELECT" keyword.</remarks>
        /// <example><code>
        /// FullTextBuilder text = FullTextBuilder.Select("Title, Author").Where(Condition.FreeText("dog, cat"));
        /// Search search = new Search();
        /// search.SearchText = text;
        /// </code></example>
        public static FullTextBuilder Select(string fields)
        {
            FullTextBuilder text = new FullTextBuilder();
            text.selectClause = fields;
            return text;
        }

        /// <summary>
        /// Creates a new instance of a FullTextBuilder by specifying
        /// a list of fields to return in a Full Text search.
        /// </summary>
        /// <param name="fields">A list of fields to return.</param>
        /// <returns></returns>
        /// <example><code>
        /// StringCollection fields = new StringCollection();
        /// fields.Add("Title");
        /// fields.Add("Author");
        /// FullTextBuilder text = FullTextBuilder.Select(fields).Where(Condition.FreeText("dog, cat"));
        /// Search search = new Search();
        /// search.SearchText = text;
        /// </code></example>
        public static FullTextBuilder Select(IList fields)
        {
            FullTextBuilder text = new FullTextBuilder();
            StringBuilder select = new StringBuilder();
            foreach(object field in fields)
            {
                select.AppendFormat("{0}, ", field.ToString());
            }
            select.Remove(select.Length - 2, 2);
            text.selectClause = select.ToString();
            return text;
        }

        /// <summary>
        /// Creates a new instance of a FullTextBuilder by specifying
        /// a string collection of fields to return in a Full Text search.
        /// </summary>
        /// <param name="fields">A string collection of fields to return.</param>
        /// <returns>Use this option in favor of the IList overload for the Select
        /// method when you know that the collection will contain strings.</returns>
        /// <example><code>
        /// StringCollection fields = new StringCollection();
        /// fields.Add("Title");
        /// fields.Add("Author");
        /// FullTextBuilder text = FullTextBuilder.Select(fields).Where(Condition.FreeText("dog, cat"));
        /// Search search = new Search();
        /// search.SearchText = text;
        /// </code></example>
        public static FullTextBuilder Select(StringCollection fields)
        {
            FullTextBuilder text = new FullTextBuilder();
            StringBuilder select = new StringBuilder();
            foreach(string field in fields)
            {
                select.AppendFormat("{0}, ", field);
            }
            select.Remove(select.Length - 2, 2);
            text.selectClause = select.ToString();
            return text;
        }


        /// <summary>
        /// Creates a new instance of a FullTextBuilder by specifying
        /// a collection of <see cref="SearchProperty"/> objects.
        /// </summary>
        /// <param name="fields"></param>
        /// <returns></returns>
        public static FullTextBuilder Select(Collection<SearchProperty> fields)
        {
            FullTextBuilder text = new FullTextBuilder();
            StringBuilder select = new StringBuilder();
            foreach(SearchProperty property in fields)
            {
                select.AppendFormat("{0}, ", property.Name);
            }
            select.Remove(select.Length - 2, 2);
            text.selectClause = select.ToString();
            return text;
        }

        /// <summary>
        /// Adds a literal WHERE clause to the search text.
        /// </summary>
        /// <param name="whereClause">A literal WHERE clause to add.  Do not include the "WHERE" keyword.</param>
        /// <returns>When using this overload, do not include a "WHERE" keyword in the literal clause.</returns>
        /// <example><code>
        /// FullTextBuilder text = FullTextBuilder.Select("Title, Author");
        /// text = text.Where("FREETEXT(DEFAULTPROPERTIES, 'dog cat') AND CONTAINS(Path, 'chaska'));
        /// Search search = new Search();
        /// search.SearchText = text;
        /// </code></example>
        public FullTextBuilder Where(string whereClause)
        {
            this.whereClause = whereClause;
            return this;
        }

        /// <summary>
        /// Adds a WHERE clause using a <see cref="Condition"/>.
        /// </summary>
        /// <param name="condition"></param>
        /// <returns></returns>
        /// <example><code>
        /// FullTextBuilder text = FullTextBuilder.Select("Title, Author");
        /// Condition c = Condition.FreeText("dog cat");
        /// text = text.Where(c);
        /// Search search = new Search();
        /// search.SearchText = text;
        /// </code></example>
        public FullTextBuilder Where(Condition condition)
        {
            this.whereClause = condition.ToString();
            return this;
        }

        /// <summary>
        /// Returns a complete full text search phrase.
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return this.BuildQuery();
        }

        string BuildQuery()
        {
            StringBuilder text = new StringBuilder();

            text.AppendFormat("SELECT {0}", this.selectClause);
            text.AppendFormat(" FROM {0}", this.fromClause);
            text.AppendFormat(" WHERE {0}", this.whereClause);
            text.AppendFormat(" ORDER BY {0}", this.orderClause);

            return text.ToString();
        }
    }
}
